#include "PacketCodec.h"
#include "http_parser.h"
#include <algorithm>
#include <map>
#include <string>
#include <boost/unordered_map.hpp>
#include <boost/algorithm/string.hpp>
#include <stdlib.h>
#include <stdio.h>
PacketCodec::PacketCodec()
{

}

PacketCodec::~PacketCodec()
{

}

RawPacket* PacketCodec::PacketDecode(const void* buffer, uint32_t size)
{
	RawPacket* pPacket = new RawPacket;
	memset(pPacket, 0x00, sizeof(*pPacket));

	pPacket->buffer = new char[size];
	pPacket->length = size;
	pPacket->buffer_length = size;
	pPacket->cmd = 1;

	memcpy(pPacket->buffer, buffer, size);

	return pPacket;
}

SendBuffer* PacketCodec::PacketEncode(const void* buffer, uint32_t size, CONTENT_TYPE type)
{
	SendBuffer* pSendBuffer = new SendBuffer;
	memset(pSendBuffer, 0x00, sizeof(*pSendBuffer));
	pSendBuffer->buffer = new char[size];
	pSendBuffer->length = size;
	memcpy(pSendBuffer->buffer, buffer, size);

	return pSendBuffer;
}

void PacketCodec::DeleteRawPacket(RawPacket * packet)
{
	if (packet)
	{
		if (packet->buffer)
		{
			delete[]packet->buffer;
		}
		delete packet;
	}
}

void PacketCodec::DeleteSendBuffer(SendBuffer * sendBuffer)
{
	if (sendBuffer)
	{
		if (sendBuffer->buffer)
		{
			delete[]sendBuffer->buffer;
		}
		delete sendBuffer;
	}
}


#define HTTP_MAX_REQ_SIZE 1024

enum HeadParseStatus { NONE = 0, FIELD, VALUE };

class HttpParseUserData
{
public:
	HttpParseUserData() { 
		lastHeadStatus = NONE; 
		m_pHeadValue = new boost::unordered_map<std::string, std::string>();
		m_pCurField = new std::string();
		m_pCurValue = new std::string();
	}

	~HttpParseUserData()
	{
		if (m_pHeadValue)
		{
			m_pHeadValue->clear();
			delete m_pHeadValue;
		}

		if (m_pCurValue)
		{
			delete m_pCurValue;
		}

		if (m_pCurField)
		{
			delete m_pCurField;
		}
	}

	void DebugPrint()
	{
		printf("url : %s\r\n", m_url.c_str());

		for (boost::unordered_map<std::string, std::string>::iterator iter = m_pHeadValue->begin();
			iter != m_pHeadValue->end(); ++iter)
		{
			printf("%s : %s\r\n", iter->first.c_str(), iter->second.c_str());
		}		
	}

public:
	HeadParseStatus lastHeadStatus;
	boost::unordered_map<std::string, std::string> *m_pHeadValue;
	std::string *m_pCurField;
	std::string *m_pCurValue;

	std::string	m_Data;
	std::string m_url;
};

static int on_my_header_field(::http_parser * parser, const char * data, size_t size)
{
	HttpParseUserData* pData = (HttpParseUserData*)(parser->data);
	if (pData)
	{
		if (pData->lastHeadStatus != FIELD)
		{
			if (!pData->m_pCurField->empty()
				&& !pData->m_pCurField->empty())
			{
				std::transform(pData->m_pCurField->begin(), pData->m_pCurField->end(),
					pData->m_pCurField->begin(), tolower);

				(*(pData->m_pHeadValue))[pData->m_pCurField->c_str()] = pData->m_pCurValue->c_str();
			}

			pData->m_pCurField->clear();
			pData->m_pCurValue->clear();
		}
		
		pData->m_pCurField->append(data, size);
		pData->lastHeadStatus = FIELD;
	}
	
	return (0);

}

static int on_parse_url(::http_parser * parser, const char * data, size_t size)
{
	HttpParseUserData* pData = (HttpParseUserData*)(parser->data);
	if (pData)
	{		
		pData->m_url.append(data, size);
	}
	return (0);
}

static int on_parse_data(::http_parser * parser, const char * data, size_t size)
{
	HttpParseUserData* pData = (HttpParseUserData*)(parser->data);
	if (pData)
	{
		pData->m_Data.append(data, size);
	}
	return (0);
}

static int on_my_header_value(::http_parser * parser, const char * data, size_t size)
{
	HttpParseUserData* pData = (HttpParseUserData*)(parser->data);
	if (pData != NULL)
	{
		pData->m_pCurValue->append(data, size);
		pData->lastHeadStatus = VALUE;
	}
	return (0);
}

IPacketCodec* CreatePacketCodec(CodecEnum codec)
{
	if (codec == Http_Codec)
	{
		return new HttpCodec();
	}

	return new PacketCodec();
}

void ReleasePacketCodec(CodecEnum codec, IPacketCodec* pCodec)
{
	if (pCodec)
	{
		if (codec == Http_Codec)
		{
			delete (HttpCodec*)pCodec;
		}
		else if (codec == TCP_Codec)
		{
			delete (PacketCodec*)pCodec;
		}
	}
}


RawPacket* HttpCodec::PacketDecode(const void* buffer, uint32_t size)
{
	http_parser parser;

	const char * pDataBuffer = (const char *)buffer;
	HttpParseUserData *pUserData = new HttpParseUserData();

	RawPacket* pPacket = new RawPacket;
	memset(pPacket, 0x00, sizeof(*pPacket));
	pPacket->length = size;

	parser.data = (void*)pUserData;
	
	http_parser_settings mySettings;
	::memset(&mySettings, 0, sizeof(mySettings));

	mySettings.on_header_field = &::on_my_header_field;
	mySettings.on_header_value = &::on_my_header_value;
	mySettings.on_body = &::on_parse_data;
	mySettings.on_url = &::on_parse_url;

	http_parser_init(&parser, HTTP_REQUEST);
	size_t parsed;
	parsed = http_parser_execute(&parser, &mySettings, pDataBuffer, size);
	if (parser.http_errno == 0)
	{
		if (pUserData->m_Data.length() > 0)
		{
			pPacket->buffer = new char[pUserData->m_Data.length()];
			memcpy(pPacket->buffer, pUserData->m_Data.data(), pUserData->m_Data.length());
			pPacket->buffer_length = pUserData->m_Data.length();
		}

		pUserData->DebugPrint();

		std::transform(pUserData->m_url.begin(), pUserData->m_url.end(),
			pUserData->m_url.begin(), tolower);

		std::vector<std::string> values;
		boost::algorithm::split(values, pUserData->m_url, boost::algorithm::is_any_of("&"));

		std::string key_proto = "/protoid=";
		for (size_t n = 0; n < values.size(); ++n)
		{
			if (values[n].compare(0, key_proto.size(), key_proto) == 0)
			{
				pPacket->cmd = atoi(values[n].c_str() + key_proto.size());
				break;
			}
		}
	}

	if (pUserData)		
	{
		delete pUserData;
		pUserData = NULL;
	} 	

	return pPacket;
}

SendBuffer* HttpCodec::PacketEncode(const void* buffer, uint32_t size, CONTENT_TYPE type)
{
	SendBuffer* pSendBuffer = new SendBuffer;

	std::string strFmt = "Content-Length : %d\r\n"
	"Content-Type : application/octet-stream\r\n\r\n";

	char szHeader[128];
	sprintf(szHeader, strFmt.c_str(), size + 4);
	int headLen = strlen(szHeader);
	pSendBuffer->length = headLen + size + 4;
	pSendBuffer->buffer = new char[headLen + size + 4];

	memcpy(pSendBuffer->buffer, szHeader, headLen);
	memcpy(pSendBuffer->buffer + headLen, buffer, size);
	memcpy(pSendBuffer->buffer + headLen + size, "\r\n", 4);

	return pSendBuffer;
}

HttpCodec::HttpCodec()
{

}

HttpCodec::~HttpCodec()
{

}

void HttpCodec::DeleteRawPacket(RawPacket * packet)
{
	if (packet)
	{
		if (packet->buffer)
		{
			delete[]packet->buffer;
		}
		delete packet;
	}
}

void HttpCodec::DeleteSendBuffer(SendBuffer * packet)
{
	if (packet)
	{
		if (packet->buffer)
		{
			delete[]packet->buffer;
		}
		delete packet;
	}
}

